/** File name: funcImageProcessing.cu
*** Author: Tran Van Hoang
*** Date: 08/05/2015
**/
#include <math.h>
#include "imageprocessing.h"
#include "cellNetwork.h"

/** Calculating distance in 2D coordinate. 
*** This can be advanced to 3D coordinate by adding z parameter.
**/
float computeDistance(CellPosition pos_1, CellPosition pos_2)
{
	float distance = -1.0;
	distance = sqrt(pow(pos_1.x - pos_2.x, 2) + pow(pos_1.y - pos_2.y, 2));
	return distance;
}

/** Getting the minimum of distance between two cell systems.
**/
float gettingMinDistance(CellArray *cells_1, CellArray *cells_2, int node_number_1, int node_number_2)
{
	float min = 0.0, d;

	for (int i = 0; i < node_number_1; i++)
	{
	    for (int j = 0; j < node_number_2; j++)
	    {
		d = computeDistance(cells_1[i].position, cells_2[j].position);
		if (min < d)
		{
		    min = d;
		}
	    }
	}

	return min;
}

void gettingClosePoints(CellArray *cells_1, CellArray *cells_2, CellArray *cells_3, int node_number_1, int node_number_2, int node_number_3, float threshold)
{
	float d, min;
	CellArray cell1, cell2;

	min = threshold;

	for (int i = 0; i < node_number_1; i++)
	{
	    cell1 = cells_1[i];
	    for (int j = 0; j < node_number_2; j++)
	    {
		cell2 = cells_2[j];
		d = computeDistance(cell1.position, cell2.position);
		if (d <= threshold && d < min)
		{
		    min = d;
		} 
	    }
	}
}

/** Checking a cell that whether it exists in a set of cells
**/
bool isExistCoordinate(int x, int y, CellArray *cells, int node_number)
{
	bool found = false;

	for (int i = 0; i < node_number; i++)
	{
	    if (x == cells[i].position.x && y == cells[i].position.y)
	    {
		found = true;
		break;
	    }
	}	

	return found;
}

/** This function will return a value indicating whether a cell is eroded or not. 
*** This computation depends on a structuring element given.
*** Value return: 0: eroded, 1: nothing
****/
int computeErosion(CellArray cell, CellArray *cells, int node_number)
{
	int x, y;
	x = cell.position.x;
	y = cell.position.y;

	if (!isExistCoordinate(x-1, y-1, cells, node_number))
	{
	   //printf("\n### %d, %d", x-1, y-1);
	   return 1;
	}
	if (!isExistCoordinate(x, y-1, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x+1, y-1, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x-1, y, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x+1, y, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x-1, y+1, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x, y+1, cells, node_number))
	{
	   return 1;
	}
	if (!isExistCoordinate(x+1, y+1, cells, node_number))
	{
	   return 1;
	}

	return 0;
}

/** This function will return a value indicating whether a cell is eroded or not. 
*** This computation depends on a structuring element given.
*** Value return: 0: eroded, 1: nothing
****/

int computeDilation(CellArray cell, CellArray *cells, int node_number)
{
	int x, y;
	x = cell.position.x;
	y = cell.position.y;

	if (isExistCoordinate(x-1, y-1, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x, y-1, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x+1, y-1, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x-1, y, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x+1, y, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x-1, y+1, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x, y+1, cells, node_number))
	{
	   return 0;
	}
	if (isExistCoordinate(x+1, y+1, cells, node_number))
	{
	   return 0;
	}

	return 1;
}
/** The function allows to erode a cell network according to a structuring element.
**  If a cell is eroded, it will be removed from the original cell network.
***/

void erodingCellNetwork(CellArray *original_cells, CellArray *eroded_cells, int node_number, int &eroded_node_number)
{
	int count = 0;

	for (int i = 0; i < node_number; i++)
	{
	    if (computeErosion(original_cells[i], original_cells, node_number) == 0)
	    {
		eroded_cells[count] = original_cells[i];
		count ++;
	    }
	}
	eroded_node_number = count;
}


/** This function allows dialate a cell network. 
***/
void dilatingCellNetwork(CellArray *original_cells, CellArray *dilated_cells, int node_number, int &dilated_node_number)
{
	CellArray cell;
	CellPosition minPos, maxPos;
	int count, index;

	//Defining the region surrounding the physical systems.	
	minPos = FindMinPosition(original_cells, node_number);
	maxPos = FindMaxPosition(original_cells, node_number);

	if (minPos.x > 0) minPos.x = minPos.x - 1;
	if (minPos.y > 0) minPos.y = minPos.y - 1;
	maxPos.x = maxPos.x + 1;
	maxPos.y = maxPos.y + 1;
	count = 0;

	for (int x = minPos.x; x < maxPos.x; x++)
	{
	     for (int y = minPos.y; y < maxPos.y; y++)
	     {
		 cell.position.x = x;
		 cell.position.y = y;

		 if (computeDilation(cell, original_cells, node_number) == 0)
		 {
		     //Resizing memory in the case of insufficience.i
		     /*
		     if (count > node_number)
		     {
		        // dilated_cells = (CellArray*) realloc(dilated_cells, (count + 1) * sizeof(CellArray));
		     }
		     */

		     index = FindIndexPosition (cell.position, original_cells, node_number);

		     if (isExistCoordinate(x, y, original_cells, node_number))
		     {			
		     	dilated_cells[count] = original_cells[index];
		     }else
		     {
			//Get color for the new cell
			cell.image.extent.height = original_cells[0].image.extent.height;
			cell.image.extent.width = original_cells[0].image.extent.width;
			for (int i = 0; i < cell.image.extent.height * cell.image.extent.width; i++)
			{
			    cell.image.pixelArray[i].red = 0;
			    cell.image.pixelArray[i].blue = 0;
			    cell.image.pixelArray[i].green = 0;
			}
			dilated_cells[count] = cell;
		     }
		     count++;
		  }
	     }
	}
	dilated_node_number = count;
}

/** This function will get the boundary of the cell network.
**/
void gettingBoundary(CellArray *original_cells, CellArray *boundary_cells, int node_number, int &boundary_node_number)
{
	CellArray *erodedCells;
	int nbErosion;

	erodedCells = (CellArray*) malloc(node_number * sizeof(CellArray));
	
	erodingCellNetwork(original_cells, erodedCells, node_number, nbErosion);
	
	boundary_node_number = node_number - nbErosion;

	//original_cells - erodedCells
	int j = 0;
	for (int i = 0; i < node_number; i++)
	{
	    if (!isExistCoordinate(original_cells[i].position.x, original_cells[i].position.y, erodedCells, nbErosion))
	    {
		boundary_cells[j] = original_cells[i];
		j++;
	    }
	}

	boundary_node_number = j;
}
